package domain

import (
	"encoding/json"
	"errors"
	"fmt"
)

// Activity types
const (
	ActivityTypeLJ = "LJ" // 立减金
	ActivityTypePT = "PT" // 平台立减
	ActivityTypeSJ = "SJ" // 随机减
)

type PTDiscountType string

const (
	PTDiscountFixed      PTDiscountType = "FIXED_AMOUNT"
	PTDiscountPercentage PTDiscountType = "PERCENTAGE"
)

// Rule structs for different activity types
type RuleLJ struct {
	CouponID string `json:"coupon_id"`
}

type RulePT struct {
	DiscountType  PTDiscountType `json:"discount_type"`
	DiscountValue int            `json:"discount_value"`         // cents or percentage(1-99)
	MinSpend      int            `json:"min_spend"`              // cents
	MaxDiscount   *int           `json:"max_discount,omitempty"` // cents, only for percentage
}

type RuleSJ struct {
	MinDiscount int `json:"min_discount"` // cents
	MaxDiscount int `json:"max_discount"` // cents
	MinSpend    int `json:"min_spend"`    // cents
	Probability int `json:"probability"`  // 1..100
}

// ValidateAndNormalize validates rule JSON by activity type and returns normalized JSON for storage.
func ValidateAndNormalize(activityType, ruleJSON string) (string, error) {
	switch activityType {
	case ActivityTypeLJ:
		var r RuleLJ
		if err := json.Unmarshal([]byte(ruleJSON), &r); err != nil {
			return "", fmt.Errorf("invalid LJ rule json: %w", err)
		}
		if r.CouponID == "" {
			return "", errors.New("coupon_id is required")
		}
		b, _ := json.Marshal(r)
		return string(b), nil
	case ActivityTypePT:
		var r RulePT
		if err := json.Unmarshal([]byte(ruleJSON), &r); err != nil {
			return "", fmt.Errorf("invalid PT rule json: %w", err)
		}
		if r.DiscountType != PTDiscountFixed && r.DiscountType != PTDiscountPercentage {
			return "", errors.New("discount_type must be FIXED_AMOUNT or PERCENTAGE")
		}
		if r.DiscountValue <= 0 {
			return "", errors.New("discount_value must be > 0")
		}
		if r.MinSpend < 0 {
			return "", errors.New("min_spend must be >= 0")
		}
		if r.DiscountType == PTDiscountPercentage {
			if r.DiscountValue <= 0 || r.DiscountValue >= 100 {
				return "", errors.New("percentage must be in 1..99")
			}
			// percentage path: optional max_discount
			if r.MaxDiscount != nil && *r.MaxDiscount < 0 {
				return "", errors.New("max_discount must be >= 0")
			}
		} else { // FIXED_AMOUNT
			if r.MaxDiscount != nil {
				return "", errors.New("max_discount not applicable for FIXED_AMOUNT")
			}
		}
		b, _ := json.Marshal(r)
		return string(b), nil
	case ActivityTypeSJ:
		var r RuleSJ
		if err := json.Unmarshal([]byte(ruleJSON), &r); err != nil {
			return "", fmt.Errorf("invalid SJ rule json: %w", err)
		}
		if r.MinDiscount <= 0 || r.MaxDiscount <= 0 {
			return "", errors.New("min/max_discount must be > 0")
		}
		if r.MinDiscount > r.MaxDiscount {
			return "", errors.New("min_discount must be <= max_discount")
		}
		if r.MinSpend < 0 {
			return "", errors.New("min_spend must be >= 0")
		}
		if r.Probability <= 0 || r.Probability > 100 {
			return "", errors.New("probability must be 1..100")
		}
		b, _ := json.Marshal(r)
		return string(b), nil
	default:
		return "", fmt.Errorf("unsupported activity_type: %s", activityType)
	}
}
